package com.gopay.cron.service.log.impl;

import com.gopay.common.domain.log.OperLogDtl;
import com.gopay.common.log.logxnew.dao.OperLogDtlDAO;
import com.gopay.cron.service.log.OperLogService;
import com.mongodb.*;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author sh.jiao
 * 存量操作日志Service实现类
 */
@Service(value = "operLogService")
public class OperLogServiceImpl implements OperLogService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static Mongo m = null;
    private static DB db = null;
    //主机ip
    private @Value("#{webProperties['mongo.host']}") String mongoHost;
    //端口号
    private @Value("#{webProperties['mongo.port']}") String mongoPort;
    //数据库名称
    private @Value("#{webProperties['mongo.databasename1']}") String mongoDatabaseName;
    //数据库集合名称
    private @Value("#{webProperties['mongo.mongocollectionname1']}") String mongoCollectionName;

    private static final int PAGESIZE = 1000;

    @Resource(name = "operLogDtlDAO")
    private OperLogDtlDAO operLogDtlDAO;

    @Override
    public void transferLog() {
        //获取数据库集合，相当于表
        startMongoDBConn();
        DBCollection dbCol = db.getCollection(mongoCollectionName);
        //查询记录数
        long size = dbCol.count();
        logger.error("共计{}条数据。",size);
        int i = (int)((size + (PAGESIZE-1)) / PAGESIZE);

        for(int j = 0;j<i;j++) {
            List<OperLogDtl> list = new ArrayList<>();
            doTransfer(dbCol,list,(j + 1),PAGESIZE);
            logger.error("需要保存到数据库的数据有{}条。",list.size());
            logger.error("开始执行保存数据......");
            operLogDtlDAO.saveOrUpdateAll(list);
            logger.error("保存成功！");
        }
        stopMondoDBConn();
    }


    private void doTransfer(DBCollection dbCol,List<OperLogDtl> list,int page, int pageSize) {
        DBCursor ret = dbCol.find()//.sort(new BasicDBObject("id", -1)) mongodb的排序很耗内存，超过默认32M会报错，中断程序
                .skip((page - 1) * pageSize).limit(pageSize);
        logger.info("开始读取第{}页，{}条数据。",page,ret.size());
        long start = System.currentTimeMillis();
        while(ret.hasNext()){
            BasicDBObject bdbObj = (BasicDBObject) ret.next();
            OperLogDtl operLogDtl = new OperLogDtl();
            if(bdbObj != null){
                String message = bdbObj.getString("message");
                if(checkNull(message)) {
                    continue;
                }
                //将json字符串转换成json对象
                JSONObject objtmp = JSONObject.fromObject(message);
                if(null == objtmp) {
                    continue;
                }
                String platform = objtmp.getString("platform");
                if(checkNull(platform) || platform.length() > 2 || "01".equals(platform)) {
                    continue;
                } else {
                    operLogDtl.setPlatform(platform);
                }
                String category = objtmp.getString("category");
                if(checkNull(category) || category.length() > 2) {
                    continue;
                } else {
                    operLogDtl.setCategory(category);
                }
                String remoteIp = objtmp.getString("remoteIp");
                if (checkNotNull(remoteIp) && remoteIp.length() > 20) {
                    remoteIp="";
                }
                operLogDtl.setRemoteIp(checkNotNull(remoteIp)?remoteIp:"");
                String localIp = objtmp.getString("localIp");
                if (checkNotNull(localIp) && localIp.length() > 20) {
                    localIp="";
                }
                operLogDtl.setLocalIp(checkNotNull(localIp)?localIp:"");
                Date operTs = bdbObj.getDate("timestamp");
                operLogDtl.setOperTs((operTs != null)?operTs:null);
                String remark = objtmp.getString("remark");
                if (checkNotNull(remark) && remark.length() > 1000) {
                    remark="";
                }
                operLogDtl.setRemark(checkNotNull(remark)?remark:"");
                String status = objtmp.getString("status");
                if (checkNotNull(status) && status.length() > 2) {
                    status="";
                }
                operLogDtl.setStatus(checkNotNull(status)?status:null);
                String threadId = objtmp.getString("threadId");
                if (checkNotNull(threadId) && threadId.length() > 50) {
                    threadId="";
                }
                operLogDtl.setThreadId(checkNotNull(threadId)?threadId:"");
                String operDesc = objtmp.getString("operDesc");
                if (checkNotNull(operDesc) && operDesc.length() > 2000) {
                    operDesc="";
                }
                operLogDtl.setOperDesc(checkNotNull(operDesc)?operDesc:"");
                String snapshotBefore = objtmp.getString("snapshotBefore");
                operLogDtl.setSnapshotBefore(checkNotNull(snapshotBefore)?snapshotBefore:null);
                String snapshotAfter = objtmp.getString("snapshotAfter");
                operLogDtl.setSnapshotAfter(checkNotNull(snapshotAfter)?snapshotAfter:null);
                //拼接操作类型json对象
                JSONObject otBaseVOobj = objtmp.getJSONObject("otBaseVO");
                if(!otBaseVOobj.isNullObject()&&!"null".equals(otBaseVOobj)&&otBaseVOobj!=null){
                    String operTypeCd = otBaseVOobj.getString("operTypeCd");
                    if(checkNull(operTypeCd)) {
                        continue;
                    } else {
                        operLogDtl.setOperTypeCd(operTypeCd);
                    }
                    String launchCustId = otBaseVOobj.getString("launchCustId");
                    if (checkNotNull(launchCustId) && launchCustId.length() > 50) {
                        launchCustId="";
                    }
                    operLogDtl.setLaunchCustId(checkNotNull(launchCustId)?launchCustId:"");
                    String launchCustName = otBaseVOobj.getString("launchCustName");
                    if (checkNotNull(launchCustName) && launchCustName.length() > 100) {
                        launchCustName="";
                    }
                    operLogDtl.setLaunchCustName(checkNotNull(launchCustName)?launchCustName:"");
                    String launchUserId = otBaseVOobj.getString("launchUserId");
                    if (checkNotNull(launchUserId) && launchUserId.length() > 50) {
                        launchUserId="";
                    }
                    operLogDtl.setLaunchUserId(checkNotNull(launchUserId)?launchUserId:"");
                    String launchUserName = otBaseVOobj.getString("launchUserName");
                    if (checkNotNull(launchUserName) && launchUserName.length() > 100) {
                        launchUserName="";
                    }
                    operLogDtl.setLaunchUserName(checkNotNull(launchUserName)?launchUserName:"");
                    String targetCustId = otBaseVOobj.getString("targetCustId");
                    if (checkNotNull(targetCustId) && targetCustId.length() > 50) {
                        targetCustId="";
                    }
                    operLogDtl.setTargetCustId(checkNotNull(targetCustId)?targetCustId:"");
                    String targetCustName = otBaseVOobj.getString("targetCustName");
                    if (checkNotNull(targetCustName) && targetCustName.length() > 100) {
                        targetCustName="";
                    }
                    operLogDtl.setTargetCustName(checkNotNull(targetCustName)?targetCustName:"");
                    String targetUserId = otBaseVOobj.getString("targetUserId");
                    if (checkNotNull(targetUserId) && targetUserId.length() > 50) {
                        targetUserId="";
                    }
                    operLogDtl.setTargetUserId(checkNotNull(targetUserId)?targetUserId:"");
                    String targetUserName = otBaseVOobj.getString("targetUserName");
                    if (checkNotNull(targetUserName) && targetUserName.length() > 100) {
                        targetUserName="";
                    }
                    operLogDtl.setTargetUserName(checkNotNull(targetUserName)?targetUserName:"");
                    String stepCode = otBaseVOobj.getString("stepCode");
                    if (checkNotNull(stepCode) && stepCode.length() > 2) {
                        stepCode="";
                    }
                    operLogDtl.setStepCode(checkNotNull(stepCode)?stepCode:"");
                    String stepName = otBaseVOobj.getString("stepName");
                    if (checkNotNull(stepName) && stepName.length() > 20) {
                        stepName="";
                    }
                    operLogDtl.setStepName(checkNotNull(stepName)?stepName:"");
                }

                //保存日志
                list.add(rebuildOperLogDtl(operLogDtl));
            }
        }
        logger.info("读取并保存mongodb数据库第{}页数据结束，耗时{}ms",page,(System.currentTimeMillis()-start));
    }

    private boolean checkNull(String value) {
        if(value == null || "".equals(value) || "null".equals(value)) {
            return true;
        }
        return false;
    }

    private boolean checkNotNull(String value) {
        return !checkNull(value);
    }

    private OperLogDtl rebuildOperLogDtl(OperLogDtl operLogDtl) {
        String remark = operLogDtl.getRemark();
        if (null == remark) {
            remark = "";
        }
        remark += "(oldData)";
        operLogDtl.setRemark(remark);

        String platform = operLogDtl.getPlatform();
        String category = operLogDtl.getCategory();
        String operTypeCd = operLogDtl.getOperTypeCd();

        // 处理导出敏感信息表编码冲突的问题
        String operDesc = operLogDtl.getOperDesc();
        if(operDesc != null && operDesc.contains("导出了敏感信息表")) {
            if ("01".equals(platform)) {
                operLogDtl.setCategory("07");
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("01070401");
            } else if ("02".equals(platform)) {
                operLogDtl.setCategory("02");
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020414");
            }
            return operLogDtl;
        }
        if("02".equals(platform) && "02".equals(category)) {//portal处理
            if ("16".equals(operTypeCd)) {//登录
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020402");
                return operLogDtl;
            } else if ("10".equals(operTypeCd)) {//修改操作员
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020515");
                return operLogDtl;
            } else if ("11".equals(operTypeCd)) {//锁定操作员
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020517");
                return operLogDtl;
            } else if ("12".equals(operTypeCd)) {//删除操作员
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020516");
                return operLogDtl;
            } else if ("13".equals(operTypeCd)) {//修改预留信息
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020412");
                return operLogDtl;
            } else if ("14".equals(operTypeCd)) {//修改支付密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020410");
                return operLogDtl;
            } else if ("15".equals(operTypeCd)) {//补全信息
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020407");
                return operLogDtl;
            } else if ("01".equals(operTypeCd)) {//找回登录密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020403");
                return operLogDtl;
            } else if ("02".equals(operTypeCd)) {//修改登录密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020408");
                return operLogDtl;
            } else if ("03".equals(operTypeCd)) {//修改登录安全问题
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020409");
                return operLogDtl;
            } else if ("05".equals(operTypeCd)) {//修改支付密码安全问题
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020411");
                return operLogDtl;
            } else if ("06".equals(operTypeCd)) {//找回支付密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("02020413");
                return operLogDtl;
            } else if ("07".equals(operTypeCd)) {//设置付款通知地址
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020512");
                return operLogDtl;
            } else if ("08".equals(operTypeCd)) {//设置商户识别码
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020513");
                return operLogDtl;
            } else if ("09".equals(operTypeCd)) {//添加操作员
                operLogDtl.setModules("05");
                operLogDtl.setOperTypeCd("02020514");
                return operLogDtl;
            }
        }
        if("06".equals(platform) && "02".equals(category)) {//DPS处理
            if ("16".equals(operTypeCd)) {//登录
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("06020405");
                return operLogDtl;
            } else if ("02".equals(operTypeCd)) {//修改登录密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("06020402");
                return operLogDtl;
            } else if ("04".equals(operTypeCd)) {//重置支付密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("06020403");
                return operLogDtl;
            } else if ("14".equals(operTypeCd)) {//修改支付密码
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("06020404");
                return operLogDtl;
            } else if ("35".equals(operTypeCd)) {//个人实名认证
                operLogDtl.setModules("04");
                operLogDtl.setOperTypeCd("06020406");
                return operLogDtl;
            }
        }
        if("01".equals(platform)) {
            operLogDtl.setCategory("06");
            operLogDtl.setModules("04");
            operLogDtl.setOperTypeCd("01060401");
        } else if ("02".equals(platform)) {
            operLogDtl.setCategory("06");
            operLogDtl.setModules("04");
            operLogDtl.setOperTypeCd("02060401");
        } else if ("06".equals(platform)) {
            operLogDtl.setCategory("02");
            operLogDtl.setModules("04");
            operLogDtl.setOperTypeCd("06020400");
        }
        return operLogDtl;
    }

    /**
     * 获取mongodb数据库连接
     */
    private void startMongoDBConn(){
        try {
            //Mongo(p1, p2):p1=>IP地址     p2=>端口
            m = new Mongo(mongoHost, Integer.parseInt(mongoPort));
            //根据mongodb数据库的名称获取mongodb对象
            db = m.getDB(mongoDatabaseName);
            //校验用户密码是否正确
        } catch (UnknownHostException e) {
            logger.error("无效连接！",e);
        } catch (MongoException e) {
            logger.error("连接失败",e);
        }
    }

    /**
     * 关闭mongodb数据库连接
     */
    private void stopMondoDBConn(){
        if (null != m) {
            if (null != db) {
                // 结束Mongo数据库的事务请求
                try {
                    db.requestDone();
                } catch(Exception e) {
                    logger.error("结束Mongo数据库的事务请求失败！",e);
                }
            }
            try
            {
                m.close();
            } catch(Exception e) {
                logger.error("关闭连接失败！",e);
            }
            m = null;
            db = null;
        }
    }

    public String getMongoHost() {
        return mongoHost;
    }

    public void setMongoHost(String mongoHost) {
        this.mongoHost = mongoHost;
    }

    public String getMongoPort() {
        return mongoPort;
    }

    public void setMongoPort(String mongoPort) {
        this.mongoPort = mongoPort;
    }

    public String getMongoDatabaseName() {
        return mongoDatabaseName;
    }

    public void setMongoDatabaseName(String mongoDatabaseName) {
        this.mongoDatabaseName = mongoDatabaseName;
    }

    public String getMongoCollectionName() {
        return mongoCollectionName;
    }

    public void setMongoCollectionName(String mongoCollectionName) {
        this.mongoCollectionName = mongoCollectionName;
    }
}
